#ifndef EXEC_H
#define EXEC_H
#include "mach.h"

typedef enum InsnType {
    INSN_ADD,
    INSN_ADDI,
    INSN_AND,
    INSN_ANDI,
    INSN_BR,
    INSN_JMP,
    INSN_JSR,
    INSN_JSRR,
    INSN_LD,
    INSN_LDI,
    INSN_LDR,
    INSN_LEA,
    INSN_NOT,
    INSN_RTI,
    INSN_ST,
    INSN_STI,
    INSN_STR,
    INSN_TRAP
} InsnType;

static char insn_name[][8] = {
    "ADD",
    "ADDI",
    "AND",
    "ANDI",
    "BR",
    "JMP",
    "JSR",
    "JSRR",
    "LD",
    "LDI",
    "LDR",
    "LEA",
    "NOT",
    "RTI",
    "ST",
    "STI",
    "STR",
    "TRAP"
};

// #define INST
// define INST to make these macros work


#define REG(i) registers[(i)]
#define DR ((INST >> 9) & 0x7)
#define SR1 ((INST >> 6) & 0x7)
#define SR2 (INST & 0x7)
#define BaseR SR1
#define SR DR
#define FLAGS ((INST >> 9) & 0x0007)
#define vec8 (INST & 0xFF)
#define imm5  ((INST & 0x010) == 0 ? (INST & 0x00F) : (INST | ~0x00F))
#define imm6  ((INST & 0x020) == 0 ? (INST & 0x01F) : (INST | ~0x01F))
#define imm9  ((INST & 0x100) == 0 ? (INST & 0x1FF) : (INST | ~0x1FF))
#define imm11 ((INST & 0x400) == 0 ? (INST & 0x3FF) : (INST | ~0x3FF))

#define SET_FLAGS() {           \
    REG (R_PSR) &= ~0x0007;     \
    if ((REG (DR) & 0x8000) != 0) \
    REG (R_PSR) |= 0x0004;      \
    else if ((REG (DR)) == 0)   \
    REG (R_PSR) |= 0x0002;      \
    else                        \
    REG (R_PSR) |= 0x0001;      \
}

#define DEF_INST(name, insn,mask,op,code)  \
    if (((insn) & (mask)) == (op)) { \
        code;                        \
        goto executed;               \
    }

#ifdef __cplusplus
extern "C" {
#endif
InsnType get_insn_type (target_size_t *insn);

target_size_t read_memory (MachineStatus *ms, target_size_t addr, target_size_t* dest);
target_size_t write_memory (MachineStatus *ms, target_size_t addr, target_size_t value);
#ifdef __cplusplus
}
#endif
#endif